//=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|
// OBJETIVO:
//   Prover as funcoes de variadas uteis pra lidar com vector's
//________________________________________________________
//A.Z. - 11/05 => Criacao
//       05/06 => static_cast para as classe template de inilogvec
//       11/07 => Funcao findLimits
//       11/07 => Biblioteca renomeada de inivec.h pra vecUtilities.h
//=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|=|
#ifndef VECUTILITIES_H
#define VECUTILITIES_H


#include <cmath>
#include <vector>
#include <iostream>
#include "aborta.hpp"
using namespace std;



//------------------------------------------------------------------------------
// Busca pelo elemento "x" dentro do intervalo do vector sortedVec
// Seja o conjunto de valores no vector o seguinte: x0, x1, x2, x3
// ESSA FUNCAO SUPOE O CONJUNTO ORDENADO: x0 <= x1 <= x2 <= x3
//
// Se passarmos um valor x para a funcao, ele pode estar em 4 situacoes:
//
// x < x0: Esta abaixo do intervalo:
//            i1 = -1
//            i2 = -1
// x > x3: Esta acima do intervalo:
//            i1 = Tamanho do vector
//            i2 = Tamanho do vector
// x==xi : Eh um valor exato do conjunto
//            i1 = i
//            i2 = i
// xi < x < xj : Esta entre dois valores do intervalo
//            i1 = i
//            i2 = j
template < class T >
void findLimits( const vector<T> &sortedVec, const T &x, int &i1, int &i2 ){

  bool found=false;  // True quando encontrou x no vector
  MTci N = sortedVec.size();


  // Verifica se x esta abaixo
  if( x < sortedVec[0] ){
    i1 = -1;
    i2 = -1;
    found = true;
  }


  // Verifica se x esta acima
  if( !found ){
    if( x > sortedVec[N-1] ){
      i1 = N;
      i2 = N;
      found = true;
    }
  }


  // Faz uma procura binaria
  if( !found ){
    int first = 0;
    int last  = N;
    while(first<=last && !found){
      int mid = (first + last) / 2;  // compute mid point.
      if     (x>sortedVec[mid]) first=mid+1;   // repeat search in top half.
      else if(x<sortedVec[mid]) last=mid-1;    // repeat search in bottom half.
      else{    // found it. return position
        i1=mid;
        i2=mid;
        found=true;
      }
    }
    if( !found ){
      i1=first-1;
      i2=first;
      found=true;
    }
  }
}




// Inicializa os vectors de maneira linear
template < class T >
inline vector<T> inivec( const T &xo, const T&xf, const int &n ){
  if( n<=1 )  aborta("O numero de elementos precisa ser maior que 1.");

  vector<T> vecT(n);
  T dx = static_cast<T>( (xf-xo)/(n-1.0) );
  vecT[0]=xo;
  for( int i=1; i<n; i++ )
    vecT[i] = vecT[i-1] + dx;

  return vecT;
}



// Inicializa os vectors de maneira logaritmica
template < class T >
inline vector<T> inilogvec( const T &xo, const T&xf, const int &n ){
  if( n<=1 )  aborta("O numero de elementos precisa ser maior que 1.");
  if( xo<=0 ) aborta("O limites precisam estar em (0,inf).");
  if( xf<=0 ) aborta("O limites precisam estar em (0,inf).");

  vector<T> vecT(n);
  T logxo = static_cast<T>( log10( static_cast<double>(xo) ) );
  T logxf = static_cast<T>( log10( static_cast<double>(xf) ) );
  T logdx = ( logxf - logxo )/(n-1.0);
  T dx    = static_cast<T>( pow( 10.0, static_cast<double>( logdx ) ) );

  vecT[0]=xo;
  for( int i=1; i<n; i++ )
    vecT[i] = vecT[i-1] * dx;

  return vecT;
}


#endif // VECUTILITIES_H
